/*
 * VoJxtaDialogView.java
 *
 * Created on February 26, 2005, 1:56 PM
 */

package jxta.chat.voice;


import net.jxta.logging.Logging;
import net.jxta.myjxta.View;
import net.jxta.myjxta.dialog.Dialog;
import net.jxta.myjxta.dialog.DialogMessage;
import net.jxta.myjxta.plugin.PluginView;
import net.jxta.myjxta.util.Resources;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * @author Jeff Moore, Ravi
 * @modified 2005-03-04 jamoore : add call control panel, audio controls
 * @modified 2005-03-14 jamoore : add config panel
 * @modified 2005-03-15 jamoore : add stats panel, UI update thread
 * @modified 2005-03-22 jamoore : add stats per interval
 * @modified 2005-03-26 jamoore : add resource strings
 */
public final class VoJxtaDialogView extends JPanel implements PluginView {

    static final Logger LOG = Logger.getLogger(VoJxtaDialogView.class.getName());

    private static final ResourceBundle STRINGS = Resources.getStrings();
    //hACK!
    public static final String INITIATED_LOCALLY = "VoJxtaDialogInitiatedLocally";

    /**
     * display strings... replace with resources
     */

    private static final String DISPLAY_SESSION_VOJXTA_DISCONNECTED = STRINGS.getString("label.vojxta.disconnected");

    private static final String DISPLAY_SESSION_VOJXTA_DISCONNECTING = STRINGS.getString("label.vojxta.disconnecting");

    private static final String DISPLAY_SESSION_VOJXTA_CONNECTED = STRINGS.getString("label.vojxta.connected");

    private static final String DISPLAY_SESSION_VOJXTA_CONNECTING = STRINGS.getString("label.vojxta.connecting");
    ;

    private static final String DEFAULT_SESSION_FILE_NAME = "MyJxtaAudioLog.speex";

    private static final String DISPLAY_SESSION_VOJXTA_STARTING = STRINGS.getString("label.vojxta.starting");

    private static final String DISPLAY_SESSION_VOJXTA_STARTED = STRINGS.getString("label.vojxta.started");

    private static final String DISPLAY_SESSION_VOJXTA_ENDING = STRINGS.getString("label.vojxta.ending");

    private static final String DISPLAY_SESSION_VOJXTA_ENDED = STRINGS.getString("label.vojxta.ended");

    private static final String DISPLAY_SESSION_VOJXTA_INCALL = STRINGS.getString("label.vojxta.incall");

    private static final String DISPLAY_SESSION_VOJXTA_HOLDING = STRINGS.getString("label.vojxta.holding");

    /**
     * Panel names for card layout
     */

    private static final String CONFIG_PANEL = "ConfigPanel";

    private static final String STATS_PANEL = "StatsPanel";

    private static final String CALL_PANEL = "CallPanel";

    /**
     * sleep time for the UI update thread
     */

    private static final int UI_UPDATE_INTERVAL = 1000;

    /**
     * sleep time while waiting for dialog pipe to connect
     */

    private static final int CONNECT_SLEEP_TIME = 200;

    /**
     * UI constructs
     */

    private JButton startCallButton = null;

    private JButton endCallButton = null;

    private JButton configButton = null;

    private JButton holdCallButton = null;

    private JButton dismissButton = null;

    private JLabel messageLabel = null;

    private JLabel incomingBufferSizeLabel = null;

    private JLabel incomingBufferCapacityLabel = null;

    private JLabel outgoingBufferSizeLabel = null;

    private JLabel outgoingBufferCapacityLabel = null;

    private JLabel sessionLogFileNameLabel = null;

    private JLabel statusLabel = null;

    private JSlider qualitySlider = null;

    private JSlider speakerVolumeSlider = null;

    private final JSlider outgoingMessageSizeSlider = null;

    private JSlider micVolumeSlider = null;

    private JCheckBox speakerMuteCheckBox = null;

    private final JCheckBox saveConvoCheckBox = null;

    private JCheckBox micMuteCheckBox = null;

    private JLabel bytesReceivedLabel = null;

    private JLabel messagesReceivedLabel = null;

    private JLabel bytesSentLabel = null;

    private final JLabel outgoingMessageSizeSliderValueLabel = null;

    private JLabel messagesSentLabel = null;

    private CardLayout cardLayout = null;

    private JPanel deckPanel = null;

    private JLabel speakerLabel = null;

    private JButton statsButton = null;

    private final JLabel encodedBufferSizeLabel = null;

    private JLabel audioBlockSizeLabel = null;

    private JLabel encodedBlockSizeLabel = null;

    private JLabel callElapsedTimeLabel = null;

    private JLabel callStartTimeLabel = null;

    private JLabel callEndTimeLabel = null;

    private JLabel outgoingMessagesPerSecondLabel = null;

    private JLabel incomingMessagesPerSecondLabel = null;

    private JLabel outgoingBytesPerSecondLabel = null;

    private JLabel incomingBytesPerSecondLabel = null;

    private JLabel compressionRatioLabel = null;

    private JLabel qualityLabel = null;

    private JLabel averageDecodeTimeLabel = null;

    private JLabel averageEncodeTimeLabel = null;

    private final JLabel encodedMessageSizeLabel = null;

    private JLabel pcmBufferSizeLabel = null;

    private JLabel sourceLineAvailableLabel = null;

    private JLabel micLabel = null;

    Insets panelInsets = null;

    Insets subComponentInsets = null;

    /**
     * dilaog on which to receive messages
     */
    //private Dialog vojxtaDialog = null;

    /**
     * controller
     */
    //private View view = null;

    /**
     * if we initiated the audio session this static is set to true. at present
     * it is set in the UI action for vojxta
     */
    private static boolean initiatedLocally = false;

    /**
     * Only one audio session at a time may be initiated
     */
    private static boolean inSession = false;

    /**
     * This table is used by the encode/decode routines to map quality levels
     * to ecoded block size in bytes. This will allow us to change the quality
     * on startup and in the future dynamically while in a call
     */
    Dictionary qualityLabelTable = null;

    /**
     * recreating a new dialog message takes too much time. use this indstaed
     */
    //private final DialogMessage templateMessage = null;

    /**
     * cycles for updates to the UI, used for stats collection
     */
    private UIUpdateThread updateThread = null;

    /**
     * protocol handler for jxta audio
     */
    private VoJxtaCallControl callControl = null;

    /**
     * Updates the UI with statistical info statistics
     */

    /** statistics */
    private long previousIncomingBytesValue = 0;

    /**
     * statistics
     */
    private long previousOutgoingBytesValue = 0;

    /**
     * statistics
     */
    private long previousIncomingMessagesValue = 0;

    /**
     * statistics
     */
    private long previousOutgoingMessagesValue = 0;
    
    private String chatedPeerName;

    /**
     * Creates a new instance of VOJXTADialogPanelent tag denoting
     */
    public VoJxtaDialogView(boolean initLocally, String remotePeerName/*View p_view, Dialog dialog*/) {

        super();
        
        chatedPeerName = remotePeerName;
        
        initiatedLocally = initLocally;

        /** lookup table for slider tick labels */
        qualityLabelTable = new Hashtable();
        qualityLabelTable.put(new Integer(0), new JLabel("Good"));
        qualityLabelTable.put(new Integer(1), new JLabel("1"));
        qualityLabelTable.put(new Integer(2), new JLabel("2"));
        qualityLabelTable.put(new Integer(3), new JLabel("3"));
        qualityLabelTable.put(new Integer(4), new JLabel("4"));
        qualityLabelTable.put(new Integer(5), new JLabel("5"));
        qualityLabelTable.put(new Integer(6), new JLabel("6"));
        qualityLabelTable.put(new Integer(7), new JLabel("7"));
        qualityLabelTable.put(new Integer(8), new JLabel("8"));
        qualityLabelTable.put(new Integer(9), new JLabel("9"));
        qualityLabelTable.put(new Integer(10), new JLabel("Best"));


        LOG.setLevel(Level.INFO);


        panelInsets = new Insets(5, 5, 5, 5);
        subComponentInsets = new Insets(3, 3, 3, 3);

        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("start vojxtadialogpanel");
        }

        // KOby - remark
        
        /*this.view = p_view;

        this.vojxtaDialog = dialog;*/

        this.callControl = new VoJxtaCallControl(this, /*this.view, dialog, */initiatedLocally);

        // KOby - remark
        
        /*if (!this.vojxtaDialog.isConnected()) {

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("Constructor : VoJxtaDialog not connected");
            }

            localActionDismiss();

        } else {*/

            UI();

            /** UI update thread for stats, call times etc*/
            updateThread = new UIUpdateThread();

            updateThread.setDaemon(true);

            setVisible(true);
            //LOG.setLevel (Level.SEVERE);
        //}
    }

    /**
     * We need to inject who inititated the audio session. This is problematic.
     * Since there is only one set of hardware (mic, speaker) there can only be
     * one session running at a time. We can logically separate sessions but
     * they all must access the same hardware. At the moment the solution is to
     * keep audio session limited to one. If another session i sactive, by calling
     * VoXJTADialog.isInSession() then we fail the invite.
     */
    public static void setInitiatedLocally(boolean initiatedLocally) {

        VoJxtaDialogView.initiatedLocally = initiatedLocally;

        setInSession(initiatedLocally);

    }

    /**
     * Returns if this audio session was inited locally (true) or initiated from
     * a remote peer (false)
     */
    protected static boolean isInitiatedLocally() {

        return initiatedLocally;
    }

    /**
     * Returns if a call is already in session.  At the moment only one audio
     * session per myjxta instance is allowed.
     */
    public static boolean isInSession() {

        return inSession;
    }

    protected static void setInSession(boolean inSession) {

        VoJxtaDialogView.inSession = inSession;
    }

    /**
     * Switch cardlayout to show a new panel
     */
    protected void localActionShowPanel(final String panelName) {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                cardLayout.show(deckPanel, panelName);

            }
        });
    }

    public void dismiss() {
        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("Dismiss called");
        }
        // any close operations go here
       // this.vojxtaDialog.clear();

        if (getCallControl() != null) {
            this.getCallControl().destroy();
        }

        this.callControl = null;
    }

    public Dialog getDialog() {

//        return this.vojxtaDialog;
    	return null;
    }

    /**
     * Signal from the UI denoting a change in the speaker volume sluder
     */
    private void localActionSpeakerGainChanged(float newValue) {

        getCallControl().adjustSpeakerGainControl(newValue);

    }

    /**
     * UI action denoting config setting have been accepted
     */
    private void localActionApplyConfigSettings() {

        getCallControl().setLocalVoiceQuality(qualitySlider.getValue());

        cardLayout.show(deckPanel, this.CALL_PANEL);

    }


    /**
     * UI action denoting the user adjusted the quality slider
     */
    private void localActionQualityChanged(int quality) {

        getCallControl().setLocalVoiceQuality(quality);

    }

    /**
     * UI action denoting user has chosen to persist this audio session. User
     * Chooses a directoy to save the session into. This is just a skeleton.
     * None of the save session logic has been implemented.
     */
    private void localActionPersistSession(boolean save) {

        if (save == true) {

            JFileChooser chooser = new JFileChooser();

            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

            chooser.setDialogTitle("Choose Audio Logging Directory");

            int returnVal = chooser.showOpenDialog(this.getParent());

            if (returnVal == JFileChooser.APPROVE_OPTION) {

                if (chooser.getSelectedFile() != null) {
                    if (chooser.getSelectedFile().isDirectory()) {

                        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {

                            sessionLogFileNameLabel.setText(
                                    chooser.getSelectedFile().getAbsolutePath() +
                                            File.separator + DEFAULT_SESSION_FILE_NAME);
                        }

                        getCallControl().setPersistSession(true,
                                chooser.getSelectedFile().getAbsolutePath() +
                                        File.pathSeparator + DEFAULT_SESSION_FILE_NAME);
                    }
                }
            }

        } else {

            getCallControl().setPersistSession(false, null);
        }
    }


    /**
     * UI action denoting the user wants to start the call. This action is for
     * two actions.  Place call for the user who initiated the session and
     * Accept call for the user on the other end. CallControl then performs the
     * protocol semantics to make the call active.
     */
    private void localActionStartCall() {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                startCallButton.setEnabled(false);
            }
        });

        if (isInitiatedLocally()) {

            getCallControl().viewActionPlaceCall(chatedPeerName);

        } else {

            getCallControl().viewActionAcceptCall(chatedPeerName);

        }
    }

    /**
     * UI action. User wishes to place the call on hold. The same button is
     * used for Hold and Resume depending on the call state
     */
    private void localActionHoldCall() {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                holdCallButton.setEnabled(false);
            }
        });


        if (holdCallButton.getText().equals("Resume Call")) {


            getCallControl().viewActionResumeCall();

        } else if (holdCallButton.getText().equals("Hold Call")) {

            getCallControl().viewActionHoldCall();
        }


    }

    /**
     * UI action. user wishes to end call.
     */
    private void localActionEndCall() {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                endCallButton.setEnabled(false);

                holdCallButton.setEnabled(false);
            }
        });

        getCallControl().viewActionHangupCall();
    }

    /**
     * Signals the app view we are done with this dialogpanel and to remove. If
     * Dismiss is invoked prior to end call attempt to go down as graceful as
     * possible alerting the remote peer(s).
     */
    private void localActionDismiss() {

        if (this.getCallControl().getProtocolState() !=
                VoJxtaCallControl.SESSION_VOJXTA_DISCONNECTED) {

            getCallControl().destroy();
        }

        //this.view.removeDialog(this.vojxtaDialog);
    }

    /**
     * Returns the call COntrol object
     */
    private VoJxtaCallControl getCallControl() {

        return this.callControl;
    }


    /**
     * Setts the call control object
     */
    private void setCallControl(VoJxtaCallControl callControl) {

        this.callControl = callControl;
    }


    /**
     * updates the UI status label. usually due to protocol changes
     */
    private void updateStatusView(final String status) {
        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            //LOG.info ("status = "+status);
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                statusLabel.setText(status);
            }
        });

    }

    /**
     * This method is the event signaling mechanism from call control. Events
     * received by the remote peer and our own call control are registerd here.
     * UI updates and button states can be changed based on protocol state.
     */
    public void protocolStateChanged(int protocolState) {

        if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_INVITE_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    startCallButton.setEnabled(true);
                }
            });

        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_START_REQUEST_SENT) {


        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_INCALL) {

            updateThread.start();

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    if (getCallControl().isSpeakerGainSupported()) {
                        speakerVolumeSlider.setEnabled(true);
                        speakerVolumeSlider.setMinimum((int) getCallControl().getSpeakerMinGain());
                        speakerVolumeSlider.setMaximum((int) getCallControl().getSpeakerMaxGain());
                        speakerVolumeSlider.setValue((int) getCallControl().getSpeakerGainValue());
                        speakerLabel.setText("SPKR (" + getCallControl().getSpeakerGainUnits() + ")");
                    }
                    if (getCallControl().isMicGainSupported()) {
                        micVolumeSlider.setEnabled(true);
                        micVolumeSlider.setMinimum((int) getCallControl().getMicMinGain());
                        micVolumeSlider.setMaximum((int) getCallControl().getMicMaxGain());
                        micVolumeSlider.setValue((int) getCallControl().getMicGainValue());
                        micLabel.setText("MIC (" + getCallControl().getMicGainUnits() + ")");
                    }


                    messageLabel.setText(
                            "Connected to " +
                                    getCallControl().getOriginator());
                    holdCallButton.setEnabled(true);
                    endCallButton.setEnabled(true);
                }
            });
        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_HOLD_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setEnabled(false);
                }
            });
        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_HOLD_ACCEPT_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setText("Resume Call");
                    holdCallButton.setEnabled(true);
                }
            });


        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_RESUME_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setEnabled(true);
                }
            });
        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_RESUME_ACCEPT_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setText("Hold Call");
                    holdCallButton.setEnabled(true);
                }
            });

        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_HANGUP_REQUEST_SENT) {

            if (updateThread != null && updateThread.isRunning()) {
                updateThread.stopThread();
            }

        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_HANGUP_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setEnabled(false);
                    endCallButton.setEnabled(false);
                }
            });

            if (updateThread != null && updateThread.isRunning()) {
                updateThread.stopThread();
            }

        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_DISCONNECT_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    holdCallButton.setEnabled(false);
                    endCallButton.setEnabled(false);
                }
            });

            if (updateThread != null && updateThread.isRunning()) {
                updateThread.stopThread();
            }

        } else if (protocolState == VoJxtaCallControl.SESSION_VOJXTA_DISCONNECTED) {

            if (updateThread != null && updateThread.isRunning()) {
                updateThread.stopThread();
            }

            setInSession(false);

            setInitiatedLocally(false);

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    messageLabel.setText(STRINGS.getString("label.vojxta.sessionended"));
                    holdCallButton.setEnabled(false);
                    endCallButton.setEnabled(false);
                    dismissButton.setEnabled(true);
                }
            });
            this.getCallControl().destroy();
        }
    }


    /**
     * left over for chaging the status message on the panel... will be removed
     */
    public void sessionStateChanged(int sessionState) {

        if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_DISCONNECTED) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_DISCONNECTED);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_DISCONNECTING) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_DISCONNECTING);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_ENDED) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_ENDED);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_ENDING) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_ENDING);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_INCALL) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_INCALL);


        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_HOLDING) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_HOLDING);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_STARTED) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_STARTED);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_STARTING) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_STARTING);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_CONNECTED) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_CONNECTED);

        } else if (sessionState == VoJxtaCallControl.SESSION_VOJXTA_CONNECTING) {

            updateStatusView(this.DISPLAY_SESSION_VOJXTA_CONNECTING);

        }


    }

    /**
     * Creates the call control panel and sets up the cardlayout.
     */
    private void UI() {

        cardLayout = new CardLayout();

        deckPanel = new JPanel(cardLayout);

        this.add(deckPanel);

        JPanel callPanel = new JPanel();

        deckPanel.add(callPanel, this.CALL_PANEL);

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();


        callPanel.setLayout(gbl);

        // add panels to this container

        JPanel messagePanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = panelInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 3;
        messagePanel.setBorder(null);
        gbl.setConstraints(messagePanel, gbc);
        callPanel.add(messagePanel);

        JPanel statusPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.insets = panelInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        statusPanel.setBorder(null);
        gbl.setConstraints(statusPanel, gbc);
        callPanel.add(statusPanel);

        JPanel micPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = panelInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 2;
        gbc.gridwidth = 1;
        micPanel.setBorder(null);
        gbl.setConstraints(micPanel, gbc);
        callPanel.add(micPanel);

        JPanel speakerPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 2;
        gbc.gridy = 1;
        gbc.insets = panelInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 2;
        gbc.gridwidth = 1;
        speakerPanel.setBorder(null);
        gbl.setConstraints(speakerPanel, gbc);
        callPanel.add(speakerPanel);

        JPanel callControlPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.insets = panelInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        callControlPanel.setBorder(null);
        gbl.setConstraints(callControlPanel, gbc);
        callPanel.add(callControlPanel);

        //add sub components to message panel
        messageLabel = new JLabel(STRINGS.getString("label.vojxta.welcome"));
        messageLabel.setFont(new Font("Arial", Font.BOLD, 18));
        messagePanel.add(messageLabel);

        // add sub components to status Panel
        statusLabel = new JLabel(STRINGS.getString("label.vojxta.disconnected"));
        statusLabel.setFont(new Font("Arial", Font.BOLD, 16));
        statusPanel.add(statusLabel);

        // add subcomponents to mic Panel

        GridBagLayout micPanelLayout = new GridBagLayout();
        micPanel.setLayout(micPanelLayout);
        micPanel.setVisible(true);

        micVolumeSlider = new JSlider(SwingConstants.VERTICAL, 0, 100, 20);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        micPanelLayout.setConstraints(micVolumeSlider, gbc);
        micVolumeSlider.setSnapToTicks(false);
        micVolumeSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                // TODO :

            }
        });
        micVolumeSlider.setEnabled(false);
        micPanel.add(micVolumeSlider);

        micMuteCheckBox = new JCheckBox();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        micPanelLayout.setConstraints(micMuteCheckBox, gbc);
        micMuteCheckBox.setSelected(false);
        micMuteCheckBox.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // TODO :
                } else if (e.getStateChange() == ItemEvent.DESELECTED) {
                    // TODO :
                }

            }
        });
        micPanel.add(micMuteCheckBox);

        JLabel micMuteLabel = new JLabel(STRINGS.getString("label.vojxta.mute"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        micPanelLayout.setConstraints(micMuteLabel, gbc);
        micPanel.add(micMuteLabel);


        micLabel = new JLabel(STRINGS.getString("label.vojxta.mic"));
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        micPanelLayout.setConstraints(micLabel, gbc);
        micPanel.add(micLabel);

        // add subcomponents to speaker Panel

        GridBagLayout speakerPanelLayout = new GridBagLayout();
        speakerPanel.setLayout(speakerPanelLayout);

        speakerVolumeSlider = new JSlider(SwingConstants.VERTICAL, 0, 0, 0);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speakerPanelLayout.setConstraints(speakerVolumeSlider, gbc);
        speakerVolumeSlider.setSnapToTicks(false);
        speakerVolumeSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                // TODO :
                localActionSpeakerGainChanged(speakerVolumeSlider.getValue());
            }
        });
        speakerVolumeSlider.setEnabled(false);
        speakerPanel.add(speakerVolumeSlider);

        speakerMuteCheckBox = new JCheckBox();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speakerPanelLayout.setConstraints(speakerMuteCheckBox, gbc);
        speakerMuteCheckBox.setSelected(false);
        speakerMuteCheckBox.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    // TODO :
                } else if (e.getStateChange() == ItemEvent.DESELECTED) {
                    // TODO :
                }

            }
        });
        speakerPanel.add(speakerMuteCheckBox);

        JLabel speakerMuteLabel = new JLabel(STRINGS.getString("label.vojxta.mute"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speakerPanelLayout.setConstraints(speakerMuteLabel, gbc);
        speakerPanel.add(speakerMuteLabel);


        speakerLabel = new JLabel(STRINGS.getString("label.vojxta.speaker"));
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = .1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speakerPanelLayout.setConstraints(speakerLabel, gbc);
        speakerPanel.add(speakerLabel);

        // add subcomponentts to call control panel

        GridBagLayout callControlLayout = new GridBagLayout();
        callControlPanel.setLayout(callControlLayout);


        startCallButton = new JButton();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;

        if (isInitiatedLocally()) {
            startCallButton.setText(STRINGS.getString("action.vojxta.placecall"));
            startCallButton.setEnabled(true);
        } else {
            startCallButton.setText(STRINGS.getString("action.vojxta.acceptcall"));
            startCallButton.setEnabled(false);
        }
        startCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                localActionStartCall();
            }
        });
        callControlLayout.setConstraints(startCallButton, gbc);
        callControlPanel.add(startCallButton);

        holdCallButton = new JButton(STRINGS.getString("action.vojxta.holdcall"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        holdCallButton.setEnabled(false);
        holdCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                localActionHoldCall();
            }
        });
        callControlLayout.setConstraints(holdCallButton, gbc);
        callControlPanel.add(holdCallButton);

        endCallButton = new JButton(STRINGS.getString("action.vojxta.endcall"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        endCallButton.setEnabled(false);
        endCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                localActionEndCall();
            }
        });
        callControlLayout.setConstraints(endCallButton, gbc);
        callControlPanel.add(endCallButton);

        dismissButton = new JButton(STRINGS.getString("action.dismiss"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        dismissButton.setEnabled(false);
        dismissButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                localActionDismiss();
            }
        });
        callControlLayout.setConstraints(dismissButton, gbc);
        callControlPanel.add(dismissButton);


        configButton = new JButton(STRINGS.getString("action.config"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        configButton.setEnabled(true);
        configButton.setVisible(false);
        configButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                localActionShowPanel(CONFIG_PANEL);

            }
        });
        callControlLayout.setConstraints(configButton, gbc);
        callControlPanel.add(configButton);

        statsButton = new JButton(STRINGS.getString("action.vojxta.stats"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        statsButton.setEnabled(true);
        statsButton.setVisible(true);
        statsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                localActionShowPanel(STATS_PANEL);

            }
        });
        callControlLayout.setConstraints(statsButton, gbc);
        callControlPanel.add(statsButton);


        JPanel configPanel = buildConfigPanel();

        deckPanel.add(configPanel, this.CONFIG_PANEL);

        JScrollPane statsScrollPane = buildStatsPanel();

        deckPanel.add(statsScrollPane, this.STATS_PANEL);

        cardLayout.show(deckPanel, this.CONFIG_PANEL);

    }

    /**
     * build the statistics panel
     */
    private JScrollPane buildStatsPanel() {

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        int gridY = 0;

        JPanel statsPanel = new JPanel();
        statsPanel.setBorder(null);
        statsPanel.setLayout(gbl);

        JLabel label = null;
        JSeparator sep = null;

        JPanel trafficPanel = new JPanel();
        trafficPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.traffic"),
                TitledBorder.CENTER, TitledBorder.CENTER));
        GridBagLayout trafficGbl = new GridBagLayout();
        trafficPanel.setLayout(trafficGbl);


        label = new JLabel(STRINGS.getString("label.vojxta.sent"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        label = new JLabel(STRINGS.getString("label.vojxta.received"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        sep = new JSeparator(SwingConstants.VERTICAL);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 2;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 3;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        label = new JLabel(STRINGS.getString("label.vojxta.messages"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        messagesSentLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(messagesSentLabel, gbc);
        trafficPanel.add(messagesSentLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.bytes"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        bytesSentLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(bytesSentLabel, gbc);
        trafficPanel.add(bytesSentLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.messages"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 4;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        messagesReceivedLabel = new JLabel("0");
        gbc.fill = gbc.WEST;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(messagesReceivedLabel, gbc);
        trafficPanel.add(messagesReceivedLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.bytes"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 4;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        bytesReceivedLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 3;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(bytesReceivedLabel, gbc);
        trafficPanel.add(bytesReceivedLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.messagespersecond"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.insets = new Insets(10, 3, 3, 3);
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 5;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 5;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        sep = new JSeparator(SwingConstants.VERTICAL);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 2;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        label = new JLabel(STRINGS.getString("label.vojxta.incoming"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        incomingMessagesPerSecondLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(incomingMessagesPerSecondLabel, gbc);
        trafficPanel.add(incomingMessagesPerSecondLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.outgoing"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 4;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        outgoingMessagesPerSecondLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 3;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(outgoingMessagesPerSecondLabel, gbc);
        trafficPanel.add(outgoingMessagesPerSecondLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.bytespersecond"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 7;
        gbc.insets = new Insets(10, 3, 3, 3);
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 5;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 8;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 5;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        sep = new JSeparator(SwingConstants.VERTICAL);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 2;
        gbc.gridy = 8;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 2;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(sep, gbc);
        trafficPanel.add(sep);

        label = new JLabel(STRINGS.getString("label.vojxta.incoming"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 9;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        incomingBytesPerSecondLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 9;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(incomingBytesPerSecondLabel, gbc);
        trafficPanel.add(incomingBytesPerSecondLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.outgoing"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 4;
        gbc.gridy = 9;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(label, gbc);
        trafficPanel.add(label);

        outgoingBytesPerSecondLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 3;
        gbc.gridy = 9;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        trafficGbl.setConstraints(outgoingBytesPerSecondLabel, gbc);
        trafficPanel.add(outgoingBytesPerSecondLabel);

        // speex panel
        JPanel speexPanel = new JPanel();
        speexPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.jspeex"),
                TitledBorder.CENTER, TitledBorder.CENTER));
        GridBagLayout speexGbl = new GridBagLayout();
        speexPanel.setLayout(speexGbl);


        label = new JLabel(STRINGS.getString("label.vojxta.averageencodetime"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = gridY;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        averageEncodeTimeLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(averageEncodeTimeLabel, gbc);
        speexPanel.add(averageEncodeTimeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.averagedecodetime"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        averageDecodeTimeLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(averageDecodeTimeLabel, gbc);
        speexPanel.add(averageDecodeTimeLabel);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        speexGbl.setConstraints(sep, gbc);
        speexPanel.add(sep);

        label = new JLabel(STRINGS.getString("label.vojxta.encodequality"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        qualityLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(qualityLabel, gbc);
        speexPanel.add(qualityLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.pcmblocksize"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        audioBlockSizeLabel = new JLabel("");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 4;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(audioBlockSizeLabel, gbc);
        speexPanel.add(audioBlockSizeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.encodedblocksize"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        encodedBlockSizeLabel = new JLabel("");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 5;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(encodedBlockSizeLabel, gbc);
        speexPanel.add(encodedBlockSizeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.compressionratio"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        compressionRatioLabel = new JLabel("0 : 1");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 6;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(compressionRatioLabel, gbc);
        speexPanel.add(compressionRatioLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.pcmbuffersize"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 7;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        pcmBufferSizeLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 7;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(pcmBufferSizeLabel, gbc);
        speexPanel.add(pcmBufferSizeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.sourcelineavailable"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 8;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(label, gbc);
        speexPanel.add(label);

        sourceLineAvailableLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 1;
        gbc.gridy = 8;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        speexGbl.setConstraints(sourceLineAvailableLabel, gbc);
        speexPanel.add(sourceLineAvailableLabel);

        // chrono panel
        JPanel chronoPanel = new JPanel();
        chronoPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.chronometer"),
                TitledBorder.CENTER, TitledBorder.CENTER));
        GridBagLayout chronoGbl = new GridBagLayout();
        chronoPanel.setLayout(chronoGbl);


        label = new JLabel(STRINGS.getString("label.vojxta.callstarttime"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(label, gbc);
        chronoPanel.add(label);

        callStartTimeLabel = new JLabel("");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = new Insets(3, 15, 3, 3);
        ;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(callStartTimeLabel, gbc);
        chronoPanel.add(callStartTimeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.elapsedtime"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = new Insets(10, 3, 3, 3);
        ;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(label, gbc);
        chronoPanel.add(label);

        callElapsedTimeLabel = new JLabel("");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = new Insets(3, 15, 3, 3);
        ;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(callElapsedTimeLabel, gbc);
        chronoPanel.add(callElapsedTimeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.callendtime"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.insets = new Insets(10, 3, 3, 3);
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(label, gbc);
        chronoPanel.add(label);

        callEndTimeLabel = new JLabel("");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.insets = new Insets(3, 15, 3, 3);
        ;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        chronoGbl.setConstraints(callEndTimeLabel, gbc);
        chronoPanel.add(callEndTimeLabel);

        // buffers panel
        JPanel bufferPanel = new JPanel();
        bufferPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.buffers"),
                TitledBorder.CENTER, TitledBorder.CENTER));
        GridBagLayout bufferGbl = new GridBagLayout();
        bufferPanel.setLayout(bufferGbl);


        label = new JLabel(STRINGS.getString("label.vojxta.incoming"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        label = new JLabel(STRINGS.getString("label.vojxta.outgoing"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        bufferGbl.setConstraints(sep, gbc);
        bufferPanel.add(sep);

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 2;
        bufferGbl.setConstraints(sep, gbc);
        bufferPanel.add(sep);

        sep = new JSeparator(SwingConstants.VERTICAL);
        gbc.fill = gbc.VERTICAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 2;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 3;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(sep, gbc);
        bufferPanel.add(sep);

        label = new JLabel("Size");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        incomingBufferSizeLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(incomingBufferSizeLabel, gbc);
        bufferPanel.add(incomingBufferSizeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.capacity"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        incomingBufferCapacityLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(incomingBufferCapacityLabel, gbc);
        bufferPanel.add(incomingBufferCapacityLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.size"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 4;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        outgoingBufferSizeLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.WEST;
        gbc.gridx = 3;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(outgoingBufferSizeLabel, gbc);
        bufferPanel.add(outgoingBufferSizeLabel);

        label = new JLabel(STRINGS.getString("label.vojxta.capacity"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 4;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(label, gbc);
        bufferPanel.add(label);

        outgoingBufferCapacityLabel = new JLabel("0");
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 3;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        bufferGbl.setConstraints(outgoingBufferCapacityLabel, gbc);
        bufferPanel.add(outgoingBufferCapacityLabel);

/*        
      label = new JLabel ("Encoded Message Size");
      gbc.fill = gbc.NONE;
      gbc.anchor = gbc.CENTER;
      gbc.gridx = 0;
      gbc.gridy = gridY;
      gbc.insets = subComponentInsets;
      gbc.weightx = 1;
      gbc.weighty = 1;
      gbc.gridheight = 1;
      gbc.gridwidth = 1;
      gbl.setConstraints (label, gbc);
      statsPanel.add (label);

      encodedMessageSizeLabel = new JLabel ("");
      gbc.fill = gbc.NONE;
      gbc.anchor = gbc.CENTER;
      gbc.gridx = 1;
      gbc.gridy = gridY++;
      gbc.insets = subComponentInsets;
      gbc.weightx = 1;
      gbc.weighty = 1;
      gbc.gridheight = 1;
      gbc.gridwidth = 1;
      gbl.setConstraints (encodedMessageSizeLabel, gbc);
      statsPanel.add (encodedMessageSizeLabel);

      outgoingMessageSizeSlider = new JSlider (SwingConstants.HORIZONTAL);
      gbc.fill = gbc.HORIZONTAL;
      gbc.anchor = gbc.CENTER;
      gbc.gridx = 0;
      gbc.gridy = gridY++;
      gbc.insets = subComponentInsets;
      gbc.weightx = 1;
      gbc.weighty = 1;
      gbc.gridheight = 1;
      gbc.gridwidth = 1;
      outgoingMessageSizeSlider.setEnabled(false);
      speakerVolumeSlider.setSnapToTicks (false);
      outgoingMessageSizeSlider.addChangeListener (new ChangeListener () {
          public void stateChanged (ChangeEvent e) {
              // TODO :
              localActionOutgoingMessageSizeAdjusted (outgoingMessageSizeSlider.getValue ());
          }
      });
      gbl.setConstraints (outgoingMessageSizeSlider, gbc);
      statsPanel.add (outgoingMessageSizeSlider);

      label = new JLabel ("Outgoing Message Size");
      gbc.fill = gbc.NONE;
      gbc.anchor = gbc.CENTER;
      gbc.gridx = 0;
      gbc.gridy = gridY;
      gbc.insets = subComponentInsets;
      gbc.weightx = 1;
      gbc.weighty = 1;
      gbc.gridheight = 1;
      gbc.gridwidth = 1;
      gbl.setConstraints (label, gbc);
      statsPanel.add (label);

      outgoingMessageSizeSliderValueLabel = new JLabel ("0");
      gbc.fill = gbc.NONE;
      gbc.anchor = gbc.CENTER;
      gbc.gridx = 1;
      gbc.gridy = gridY++;
      gbc.insets = subComponentInsets;
      gbc.weightx = 1;
      gbc.weighty = .1;
      gbc.gridheight = 1;
      gbc.gridwidth = 1;
      gbl.setConstraints (outgoingMessageSizeSliderValueLabel, gbc);
      statsPanel.add (outgoingMessageSizeSliderValueLabel);

*/
        JPanel actionPanel = new JPanel();
        GridBagLayout actionGbl = new GridBagLayout();
        actionPanel.setLayout(actionGbl);

        JButton showCallPanelButton = new JButton(STRINGS.getString("action.vojxta.back"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = gridY++;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(showCallPanelButton, gbc);
        showCallPanelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                localActionShowPanel(CALL_PANEL);
            }
        });
        actionPanel.add(showCallPanelButton);

        // add the panels

        gridY = 0;

        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(trafficPanel, gbc);
        statsPanel.add(trafficPanel);

        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(speexPanel, gbc);
        statsPanel.add(speexPanel);

        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(chronoPanel, gbc);
        statsPanel.add(chronoPanel);

        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(bufferPanel, gbc);
        statsPanel.add(bufferPanel);

        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.EAST;
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(actionPanel, gbc);
        statsPanel.add(actionPanel);

        JScrollPane scrollPane = new JScrollPane(statsPanel);


        return scrollPane;


    }

    /**
     * builds the config panel
     */
    private JPanel buildConfigPanel() {

        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();

        JPanel configPanel = new JPanel();

        configPanel.setLayout(gbl);

        int gridY = 0;

        JPanel messagePanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        messagePanel.setBorder(null);
        gbl.setConstraints(messagePanel, gbc);
        configPanel.add(messagePanel);

        JPanel persistPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        persistPanel.setBorder(new TitledBorder(STRINGS.getString("label.vojxta.persistsession")));
        gbl.setConstraints(persistPanel, gbc);
        configPanel.add(persistPanel);

        JPanel qualityPanel = new JPanel();
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        qualityPanel.setBorder(new TitledBorder(STRINGS.getString("label.vojxta.voicequality")));
        gbl.setConstraints(qualityPanel, gbc);
        configPanel.add(qualityPanel);

        JPanel actionPanel = new JPanel();
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbl.setConstraints(actionPanel, gbc);
        configPanel.add(actionPanel);

        // add subcomponents to messagePanel
        GridBagLayout messagePanelgbl = new GridBagLayout();
        // statelabel
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        messagePanelgbl.setConstraints(this.statusLabel, gbc);
        messagePanel.add(this.statusLabel);

        // add subcomponents to persist panel
        GridBagLayout persistPanelgbl = new GridBagLayout();

        sessionLogFileNameLabel = new JLabel(DEFAULT_SESSION_FILE_NAME);

        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        persistPanelgbl.setConstraints(sessionLogFileNameLabel, gbc);
        persistPanel.add(sessionLogFileNameLabel);


        final JCheckBox saveConvoCheckBox = new JCheckBox(STRINGS.getString("label.vojxta.saveconversation"));
        gbc.fill = gbc.NONE;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        saveConvoCheckBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionPersistSession(saveConvoCheckBox.isSelected());

            }
        });
        persistPanelgbl.setConstraints(saveConvoCheckBox, gbc);
        persistPanel.add(saveConvoCheckBox);

        // add subcomponents to quality panel

        GridBagLayout qualityPanelgbl = new GridBagLayout();

        qualitySlider = new JSlider(SwingConstants.HORIZONTAL, getCallControl().MINIMUM_QUALITY, getCallControl().MAXIMUM_QUALITY, getCallControl().DEFAULT_QUALITY);
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        qualitySlider.setLabelTable(qualityLabelTable);
        qualitySlider.setPaintLabels(true);
        qualitySlider.setPaintTicks(true);
        qualitySlider.setSnapToTicks(true);
        qualitySlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent ce) {

                localActionQualityChanged(qualitySlider.getValue());

            }
        });
        qualityPanelgbl.setConstraints(qualitySlider, gbc);
        qualityPanel.add(qualitySlider);

        // add subcomponents to apply settings panel

        GridBagLayout actionPanelGbl = new GridBagLayout();

        JButton actionButton = new JButton(STRINGS.getString("action.ok"));
        gbc.fill = gbc.HORIZONTAL;
        gbc.anchor = gbc.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = subComponentInsets;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        actionButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionApplyConfigSettings();
            }
        });
        actionPanelGbl.setConstraints(actionButton, gbc);
        actionPanel.add(actionButton);

        return configPanel;
    }
    
    public void remotePlaceCall(){
    	startCallButton.setEnabled(true);
    }


    class UIUpdateThread extends Thread {

        private boolean threadRun = true;

        public boolean isRunning() {
            return threadRun;
        }

        public void stopThread() {
            threadRun = false;
        }

        public void run() {

            while (threadRun) {
                EventQueue.invokeLater(new Runnable() {
                    public void run() {

                        long tmp = 0;

                        bytesSentLabel.setText(String.valueOf(callControl.getMicControl().getNumberOfBytesSent()));

                        messagesSentLabel.setText(String.valueOf(callControl.getMicControl().getNumberOfMessagesSent()));

                        bytesReceivedLabel.setText(String.valueOf(callControl.getSpeakerControl().getNumberOfBytesReceived()));

                        messagesReceivedLabel.setText(String.valueOf(callControl.getSpeakerControl().getNumberOfMessagesReceived()));

                        audioBlockSizeLabel.setText(String.valueOf(callControl.getAudioBlockSize()));

                        encodedBlockSizeLabel.setText(String.valueOf(callControl.getEncodedBlockSize()));

                        callEndTimeLabel.setText(callControl.getCallEndTimeString());

                        callStartTimeLabel.setText(callControl.getCallStartTimeString());

                        callElapsedTimeLabel.setText(callControl.getCallElapseTimeString());

                        tmp = callControl.getMicControl().getNumberOfMessagesSent();
                        outgoingMessagesPerSecondLabel.setText(String.valueOf(
                                tmp - previousOutgoingMessagesValue));
                        previousOutgoingMessagesValue = tmp;

                        tmp = callControl.getSpeakerControl().getNumberOfMessagesReceived();
                        incomingMessagesPerSecondLabel.setText(String.valueOf(
                                tmp - previousIncomingMessagesValue));
                        previousIncomingMessagesValue = tmp;

                        tmp = callControl.getMicControl().getNumberOfBytesSent();
                        outgoingBytesPerSecondLabel.setText(String.valueOf(
                                tmp - previousOutgoingBytesValue));
                        previousOutgoingBytesValue = tmp;

                        tmp = callControl.getSpeakerControl().getNumberOfBytesReceived();
                        incomingBytesPerSecondLabel.setText(String.valueOf(
                                tmp - previousIncomingBytesValue));
                        previousIncomingBytesValue = tmp;

                        compressionRatioLabel.setText(String.valueOf(callControl.getCompressionRatio()) + " : 1");

                        qualityLabel.setText(String.valueOf(callControl.getQualityOfService()));

                        averageDecodeTimeLabel.setText(String.valueOf(callControl.getAverageDecodeTime()));

                        averageEncodeTimeLabel.setText(String.valueOf(callControl.getAverageEncodeTime()));

                        outgoingBufferSizeLabel.setText(String.valueOf(callControl.getOutgoingBufferSize()));

                        outgoingBufferCapacityLabel.setText(String.valueOf(callControl.getOutgoingBufferCapacity()));

                        incomingBufferSizeLabel.setText(String.valueOf(callControl.getIncomingBufferSize()));

                        incomingBufferCapacityLabel.setText(String.valueOf(callControl.getIncomingBufferCapacity()));

                        pcmBufferSizeLabel.setText(String.valueOf(callControl.getSpeakerControl().getPCMBufferSize()));

                        sourceLineAvailableLabel.setText(String.valueOf(callControl.getSpeakerControl().getSourceLineAvailable()));

                    }
                });

                try {

                    Thread.sleep(UI_UPDATE_INTERVAL);

                } catch (InterruptedException ix) {
                    ix.printStackTrace();
                }
            }

        }
    }

}//class

